//
// LVGL 用户界面
//

#include "UI.h"
#include <Ticker.h>

UI ui;
Ticker tick; /* timer for interrupt handler */
extern Encoder knob;
unsigned long knobPos = 0;
extern unsigned long dit_tm;
extern unsigned int key_mode;
extern BleKeyboard Keyboard;
static lv_disp_draw_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];
static lv_color_t buf2[LV_HOR_RES_MAX * 10];
/* Interrupt driven periodic handler */
static void lv_tick_handler(void)
{
    //Serial.println("tick 5 ms");
    lv_tick_inc(5);
}
void ui_flush_cb(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    ui.disp_flush(disp, area, color_p);
}

void ui_encoder_cb(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
    ui.encoder_read(drv, data);
    // return false;
    //return true;
}

void s_wpm_change_cb(lv_event_t *event) //(lv_event_t *event)
{
    ui.wpm_change_cb(event);
}

void s_key_change_cb(lv_event_t *event) //(lv_event_t *event)
{
    ui.key_change_cb(event);
}

/***
* 初始化
*/
void UI::init()
{
    pinMode(27, INPUT_PULLUP);
#if USE_LV_LOG != 0
    lv_log_register_print_cb(this->ui_log); /* register print function for debugging */
#endif
    // 初始化 lvgl
    lv_init();

    // ʹ�� eTFT ��ʼ����Ļ����
    tft.begin();        /* TFT init */
    tft.setRotation(3); /* Landscape orientation */
    tft.fillScreen(TFT_BLUE);

    lv_disp_draw_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
    /*Initialize the display*/
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = 160;
    disp_drv.ver_res = 128;
    // disp_drv.vdb_wr = NULL;
    disp_drv.flush_cb = ui_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    lv_disp_drv_register(&disp_drv);
    /*Initialize the (dummy) input device driver*/
    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_ENCODER;
    indev_drv.read_cb = ui_encoder_cb;
    lv_indev_t *indev = lv_indev_drv_register(&indev_drv);

    /*Initialize the graphics library's tick*/
    // tick.attach_ms(5, lv_tick_handler);

    g = lv_group_create();
    lv_indev_set_group(indev, g);
    this->render_main();
}

/// <summary>
/// ����������ص�����
/// </summary>
/// <param name="drv"></param>
/// <param name="data"></param>
bool UI::encoder_read(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
    Serial.println("encoder 00");
    static int32_t last_diff = 0;
    static int32_t last_val = 0;
    static int32_t cur_val = 0;
    //static int lastBtn;
    cur_val = knob.read();
    int32_t diff = cur_val - last_val; // read the rotary encoder position;
    int32_t absDiff = abs(diff);
    int32_t enc_diff = 0;
    Serial.println("encoder 11");
    if (absDiff != 0)
    {
        if (absDiff <= 4)
        {
            enc_diff = diff / absDiff;
        }
        else
        {
            enc_diff = diff / 4;
        }
    }
    Serial.println("encoder 22");
    if (last_diff != enc_diff)
    {
        data->enc_diff = enc_diff;
        last_diff = enc_diff;
    }
    else
    {
        data->enc_diff = 0;
        last_diff = 0;
    }
    last_val = cur_val;
    Serial.println("encoder 33");
    data->state = (0 == digitalRead(27) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL); // read encoder push button status
    Serial.println("encoder 44");
    //knob.write(0);
    Serial.println("encoder 55");
    return false; /*No buffering now so no more data read*/
}
/// <summary>
/// ����ˢ��
/// </summary>
/// <param name="disp"></param>
/// <param name="area"></param>
/// <param name="color_p"></param>
void UI::disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    Serial.println("do disp");
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);
    Serial.println("do disp11");
    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);

    //tft.pushColors(&color_p->full, w * h);
    //tft.pushColors((uint8_t*)&color_p->full, w * h);
    Serial.println("do disp22");
    /*
    uint32_t wh = w * h;
    while (wh--)
        tft.pushColor(color_p++->full);
    */
    tft.pushColors((uint16_t *)&color_p->full, w * h, true);

    tft.endWrite();
    Serial.println("do disp33");
    lv_disp_flush_ready(disp);
    Serial.println("do disp44");
}
/// <summary>
/// 主界面
/// </summary>
void UI::render_main()
{
    Serial.println("wpm init");
    // 码率标签
    lv_obj_t *labWpm = lv_label_create(lv_scr_act());
    lv_label_set_text(labWpm, "WPM: ");
    lv_obj_align(labWpm, LV_ALIGN_TOP_LEFT, 5, 5);

    /*A roller on the left with left aligned text, and custom width*/
    const char *opts = "10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n52\n53\n54\n55\n56\n57\n58\n59\n60\n61\n62\n63\n64\n65\n66\n67\n68\n69\n70\n71\n72\n73\n74\n75\n76";
    roller = lv_roller_create(lv_scr_act());
    lv_roller_set_options(roller, opts, LV_ROLLER_MODE_INFINITE); // LV_ROLLER_MODE_INFINITE LV_ROLLER_MODE_NORMAL
    lv_roller_set_visible_row_count(roller, 1);
    lv_obj_align(roller, LV_ALIGN_TOP_LEFT, 50, 5);
    lv_obj_set_height(roller, 16);
    lv_obj_set_width(roller, 80);

    //lv_obj_add_event_cb(roller, s_wpm_change_cb); /*Assign an event callback*/
    lv_obj_add_event_cb(roller, s_wpm_change_cb, LV_EVENT_ALL, NULL);
    lv_roller_set_selected(roller, 10, LV_ANIM_OFF);
    lv_group_add_obj(g, roller);

    lv_obj_t *lab_key = lv_label_create(lv_scr_act());
    lv_label_set_text(lab_key, "KEY: ");
    lv_obj_align(lab_key, LV_ALIGN_TOP_LEFT, 5, 25);

    const char *mdOpt = "Auto\nStraight";
    rollMode = lv_roller_create(lv_scr_act());
    lv_roller_set_options(rollMode, mdOpt, LV_ROLLER_MODE_INFINITE); // LV_ROLLER_MODE_INFINITE LV_ROLLER_MODE_NORMAL
    lv_roller_set_visible_row_count(rollMode, 1);
    lv_obj_align(rollMode, LV_ALIGN_TOP_LEFT, 50, 25);
    lv_obj_set_height(rollMode, 16);
    lv_obj_set_width(rollMode, 80);
    // lv_obj_set_event_cb(rollMode, s_key_change_cb);
    lv_obj_add_event_cb(rollMode, s_key_change_cb, LV_EVENT_ALL, NULL);
    lv_roller_set_selected(rollMode, 0, LV_ANIM_OFF);
    lv_group_add_obj(g, rollMode);

    ta = lv_textarea_create(lv_scr_act());
    lv_textarea_set_one_line(ta, true);
    lv_obj_align(ta, LV_ALIGN_CENTER, 0, 0);
    lv_obj_add_state(ta, LV_STATE_FOCUSED); /*To be sure the cursor is visible*/
    lv_textarea_set_text(ta, "");
    lv_obj_set_width(ta, 150);
    lv_obj_t *labCallSign = lv_label_create(lv_scr_act());
    lv_label_set_text(labCallSign, "Call Sign:BH8UAF");
    lv_obj_align(labCallSign, LV_ALIGN_BOTTOM_RIGHT, -5, -5);
    Serial.println("END RENDER wpm init");
}

void UI::wpm_change_cb(lv_event_t *event)
{
    char buf[4];
    lv_roller_get_selected_str(roller, buf, 4);
    int wpm = atoi(buf);
    dit_tm = (60000 / (50 * wpm)); //(60 seconds * 1000)/(PARIS mode * WPM)
}
void UI::key_change_cb(lv_event_t *event)
{
    lv_event_code_t code = lv_event_get_code(event);
    //lv_obj_t *obj = lv_event_get_target(event);
    if (code == LV_EVENT_VALUE_CHANGED)
    {
        /*
        char buf[32];
        lv_roller_get_selected_str(obj, buf, sizeof(buf));
        LV_LOG_USER("Selected month: %s\n", buf);
        */
        key_mode = (lv_roller_get_selected(rollMode) + 1);
        Serial.println("key mode is ");
        Serial.println(key_mode);
    }
}

void UI::ui_loop()
{
    Serial.println("ui_loop");
    // lv_task_handler(); /* let the GUI do its work */
    lv_timer_handler();
    Serial.println("ui_loop end ====================");
}

void UI::fire_char(char c)
{
    lv_textarea_add_char(ta, c);
    Keyboard.write(c);
}
#if USE_LV_LOG != 0
void UI::ui_log(lv_log_level_t level, const char *file, uint32_t line, const char *dsc)
{
}
#endif
